/**
 * grunt 入口文件
 * 用预订以一些需要 grunt 自动执行的任务
 * 导出一个接受 grunt形参 的函数，形参对象中是 grunt 提供的可创建一些构建任务的 api
 */

module.exports = grunt => {
  /**
    * 注册函数
    * @param {string} 参数1：指定任务名
    * @param {function} 参数2：任务发生时自动执行的函数
    */
  grunt.registerTask('foo', () => {
    console.log('hello grunt')
  })
  /**
   * @param {string} 参数2如果是字符串，则将会作为任务描述
   */
  grunt.registerTask('bar', '任务描述', () => {
    console.log('has description')
  })
  // /**
  //  * @param {string} 参数1如果是'default'，则会作为 grunt 的默认任务，运行时不需指定任务名
  //  */
  // grunt.registerTask('default', () => {
  //   console.log('this is default task')
  // })

  /**
   * @param {string} 参数1是 default
   * @param {Array} 参数2是数组，指定其他任务名，grunt会依次执行数组中的任务
   */
  // grunt.registerTask('default', ['foo', 'bar'])

  /**
   * 异步任务此时这样的写法不会打印结果，因为 grunt 默认是同步任务
   */
  grunt.registerTask('aync-task', () => {
    setTimeout(() => {
      console.log('async message')
    }, 1000);
  })

  /**
   * 异步任务需要用 this 标识，此时函数不能是箭头函数
   */
  grunt.registerTask('async-task2', function () {
    const done = this.async()
    setTimeout(() => {
      console.log('async message2')
      // 打印消息之后还需执行以下 done，让grunt知道这是个异步任务
      done()
    }, 1000);
  })

  /**
   * 标记任务失败，通过 return false 来标记
   */
  grunt.registerTask('bad', () => {
    console.log('bad message')
    return false
  })

  /**
   * 标记任务失败，如果当前任务在任务列表中，则会阻塞后续任务执行
   * 根据命令行提示，若任务失败，可使用 --force 继续后续任务
   */
  grunt.registerTask('default', ['foo', 'bad', 'bar'])

  /**
   * 异步任务标记任务失败，需要给异步回调函数指定 `false` 实参
   */
  grunt.registerTask('bad-async', function () {
    const done = this.async()
    setTimeout(() => {
      console.log('bad-async message')
      done(false)
    }, 1000);
  })


  /**
   * 配置选项，接收对象参数，键与任务名相同，值可以是任意类型
   */
  grunt.initConfig({
    foo1: 'bar1'
  })
  grunt.registerTask('foo1', () => {
    // 使用 .config() 可以获取配置项，接收字符串参数，为任务名
    const foo1 = grunt.config('foo1')
    console.log(foo1)
  })

  /**
   * 值也可以是对象
   */
  grunt.initConfig({
    foo2: {
      bar2: '123'
    }
  })
  grunt.registerTask('foo2', () => {
    const foo2 = grunt.config('foo2.bar2')
    const foo2_2 = grunt.config('foo2').bar2
    console.log(foo2)
    console.log(foo2_2)
  })


  /**
   * 多目标模式，可以让任务根据配置形成多个子任务
   * 同样两个参数，任务名 & 函数
   */
  grunt.registerMultiTask('build', () => {
    console.log('build task')
  })

  // 配置多个任务，此时属性值必须是个对象,对象中数据为 build任务的目标任务
  grunt.initConfig({
    build2: {
      css: '1',
      js: '2'
    }
  })
  grunt.registerMultiTask('build2', function () {
    // 函数中可通过 this.target 拿到当前执行的目标
    // 使用 this.data 拿到当前target的配置数据
    console.log('build2 task', `target: ${this.target}, data: ${this.data}`)
  })

  /**
   * 多目标任务，指定目标任务若为 options，则会作为配置选项存在
   * 若目标也是个对象，也可以在目标对象内添加options，会覆盖掉外层对象的options
   */
  grunt.initConfig({
    build3: {
      options: {
        foo: 'bar'
      },
      css: {
        options: {
          cssoption: 'css_options_value'
        }
      },
      js: '2'
    }
  })
  grunt.registerMultiTask('build3', function () {
    // 可通过 this.options 拿到对应的配置选项，可拿到当前任务配置选项的对象
    console.log(this.options())
  })
}